//
//  KLMProvisionManager.swift
//  KLM
//
//  Created by 朱雨 on 2021/7/19.
//

import UIKit
import nRFMeshProvision

protocol KLMProvisionManagerDelegate: AnyObject {
    
    func provisionManager(_ manager: KLMProvisionManager, didFailChange error: MessageError)
    
    func provisionManagerNodeAddSuccess(_ manager: KLMProvisionManager)
}

class KLMProvisionManager: NSObject {
    
    private var provisioningManager: ProvisioningManager!
    var bearer: ProvisioningBearer!
    /// 配网设备
    var discoveredPeripheral: DiscoveredPeripheral!
    weak var delegate:  KLMProvisionManagerDelegate?
    
    //单例
    init(discoveredPeripheral: DiscoveredPeripheral, bearer: ProvisioningBearer) {
        super.init()
        self.discoveredPeripheral = discoveredPeripheral
        self.bearer = bearer
        self.bearer.delegate = self
    }
}

extension KLMProvisionManager {
    
    func identify() {
        
        SVProgressHUD.show(withStatus: "identify")
        
        let manager = MeshNetworkManager.instance
        self.provisioningManager = try! manager.provision(unprovisionedDevice: self.discoveredPeripheral.device, over: self.bearer)
        self.provisioningManager.delegate = self
        self.provisioningManager.logger = MeshNetworkManager.instance.logger
        
        DispatchQueue.main.asyncAfter(deadline: 1) {
            
            do {
                try self.provisioningManager.identify(andAttractFor: 5)
            } catch {
                
                let err = MessageError()
                err.message = error.localizedDescription
                self.delegate?.provisionManager(self, didFailChange: err)
            }
        }
    }
}

extension KLMProvisionManager: ProvisioningDelegate {
    func authenticationActionRequired(_ action: AuthAction) {
        
    }
    
    func inputComplete() {
        
    }
    
    func provisioningState(of unprovisionedDevice: UnprovisionedDevice, didChangeTo state: ProvisioningState) {
        
        switch state {
        case .capabilitiesReceived(_)://identify完成
            
            KLMLog("identify success")
            SVProgressHUD.show(withStatus: "provision")
            
            //provision
            if provisioningManager.networkKey == nil {
                let network = MeshNetworkManager.instance.meshNetwork!
                let networkKey = try! network.add(networkKey: Data.random128BitKey(), name: "Primary Network Key")
                provisioningManager.networkKey = networkKey
            }
            
            ///给设备分配单播地址 - 从服务器获取的
            KLMRequest.getUnicastAddress { response in
//            KLMService.applyUnicastAddress { response in
                if let address: UInt16 = response as? UInt16 {
                    self.provisioningManager.unicastAddress = address
                    do {

                        try self.provisioningManager.provision(usingAlgorithm:       .fipsP256EllipticCurve,
                                                               publicKey:            .noOobPublicKey,
                                                               authenticationMethod: .noOob)
                    } catch {
                        
                        if let error = error as? ProvisioningError {
                            
                            let err = MessageError()
                            err.message = error.errorDescription
                            
                            switch error {
                            case ProvisioningError.addressNotSpecified:
                                err.message = "设备地址超出限制，请重新新建店铺测试"
                            default:
                                break
                            }
                            self.delegate?.provisionManager(self, didFailChange: err)
                        }
                    }
                }
            } failure: { error in
                let err = MessageError()
                err.message = "获取设备地址失败"
                self.delegate?.provisionManager(self, didFailChange: err)
            }
            
        case .complete://provison完成
            
            KLMLog("provision success")
            
            //关闭和未配网设备的连接--这个时候开始连接1828设备
            self.bearer.close()
        
        case let .fail(error):
            
            self.bearer.close()
            
            let err = MessageError()
            err.message = error.localizedDescription
            self.delegate?.provisionManager(self, didFailChange: err)
            
        default:
            break
        }
    }
}

extension KLMProvisionManager: GattBearerDelegate {
    
    func bearer(_ bearer: Bearer, didClose error: Error?) {
        KLMLog("unprovision bearer close")
        guard case .complete = provisioningManager.state else {
            return
        }
        //节点添加完成 - save之后数据才会保存
        if MeshNetworkManager.instance.save() {
            DispatchQueue.main.asyncAfter(deadline: 2) {
                if let network = MeshNetworkManager.instance.meshNetwork {
                    
                    if let node = network.node(for: self.discoveredPeripheral.device) {
                        ///添加设备到服务器
                        var name = KLMLocalizable.LANGLOC("Unknown device")
                        if let aa = self.discoveredPeripheral.device.name {
                            name = KLMTool.getDeviceName(name: aa)!
                        }
                        
                        //本地配置数据节点名称变更
                        node.name = name
                        
                        KLMLog("node add success")
                        DispatchQueue.main.asyncAfter(deadline: 1) {
                            
                            self.delegate?.provisionManagerNodeAddSuccess(self)
                        }
                    }
                }
            }
        } else {
            let err = MessageError()
            err.message = "Mesh configuration could not be saved."
            self.delegate?.provisionManager(self, didFailChange: err)
        }
    }
    
    func bearerDidOpen(_ bearer: Bearer) {
        
    }
}
